package com.chaosj.tools

import com.google.common.base.CaseFormat
import com.google.common.base.Splitter
import com.google.common.base.StandardSystemProperty
import com.google.common.base.Strings
import com.google.common.collect.Lists
import com.google.common.collect.Maps

import java.lang.management.ManagementFactory
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardOpenOption
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.Phaser
import java.util.stream.Collectors

/**
 * @Description:
 * @author: caoyangjie
 * @date: 2019年11月2019/11/28日 09:02
 * @Copyright: © 赢时胜
 */
class FileRewrite {
    static void main(args){
        List<String> filePaths = searchAllPojos("E:\\platform\\workspaces\\Code\\server\\source")
        String rewriteFileDir = "E:\\tmp"
        rewriteFile(filePaths,rewriteFileDir)
    }

    static List<String> searchAllPojos(String basePath){
        List<String> contains = null
        List<String> baseScanFilePaths = Files.list(Paths.get(basePath))
                .filter({ path -> path.toFile().isDirectory()})
                .filter({ path->
                    (contains==null || contains.isEmpty())?true:contains.stream().filter({k->path.toFile().getAbsolutePath().contains(k)}).findAny().isPresent()
                })
                .map({ path -> path.toFile().getAbsolutePath()}).collect(Collectors.toList())
        return scanFilePaths(baseScanFilePaths)
    }

    static List<String> scanFilePaths(List<String> scanFilePaths){
        Queue<String> concurrentSet = new ConcurrentLinkedQueue<>()
        int canUseCPU = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors()
        def phaser = new Phaser(canUseCPU>scanFilePaths.size()?scanFilePaths.size():canUseCPU)
        scanFilePaths.parallelStream().forEach({path->
            def fs = new FileSearchFilter(path, phaser, {file ->
                try {
                    // 所有的实现了 BasePojo 的类清单
                    return file.getName().endsWith("java") && Files.readAllLines(file.toPath()).stream().limit(50).filter({line->
                        line.contains(" extends BasePojo") && line.contains("class")
                    }).findAny().isPresent()
                } catch (IOException e) {
                }
                return false
            } ,{q,f->
                q.add(f.getAbsoluteFile().getAbsolutePath())
            })
            fs.run ( )
            concurrentSet.addAll( fs.getResults() )
        })
        List<String> result = Lists.newArrayList()
        result.addAll(concurrentSet)
        result
    }

    static void rewriteFile(List<String> files,String rewriteFileDir){
        files.stream().map({path-> new File(path)}).forEach({file->
            Path filePath = FileSystems.getDefault().getPath(rewriteFileDir+ StandardSystemProperty.FILE_SEPARATOR.value()+file.getName())
            if( !filePath.toFile().exists() ){
                Files.delete(filePath)
            }
            filePath = Files.createFile(filePath)
            List<String> allLine = Lists.newArrayList()
            Map<String,String> convertAttrMap = Maps.newHashMap()
            convertAttrMap.put("com.yss.framework.api.common.co.BasePojo","com.yss.fomp.api.dto.BasePojo")
            Files.readAllLines(file.toPath()).forEach({line->
                allProcesses().stream().filter({p->p.filter(line,convertAttrMap)}).findFirst().orElse(new ProcessNull()).process(line,allLine,convertAttrMap)
            })
            Files.write(filePath,allLine,StandardOpenOption.APPEND)
        })
    }

    static List<IProcessLine> allProcesses(){
        return Arrays.asList(
            new ProcessAttr(),new ProcessSetMethod(),new ProcessGetMethod()
        )
    }

    static String underToCamel(String value){
        CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL,value)
    }

    static String underToUCamel(String value){
        value = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN,value)
        CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL,value)
    }

    static class ProcessNull implements IProcessLine{
        Map filterMap = Maps.newHashMap()

        @Override
        boolean filter(String line,Map<String,String> map) {
            return true
        }

        @Override
        process(String line, List<String> collects,Map<String,String> map) {
            filterMap.put("c_","C_")
            filterMap.put("n_","N_")
            map.keySet().stream().forEach({key->
                filterMap.keySet().stream().forEach({upperKey->
                    line = line.replace("this."+upperKey,"this."+filterMap.get(upperKey))
                    line = line.replace("return this."+upperKey,"return this."+filterMap.get(upperKey))
                    line = line.replace("return "+upperKey,"return this."+filterMap.get(upperKey))
                })
                if( line.contains(key) && !line.contains("com.yss.framework.api.common.co.BasePojo")){
                    line = line.replace(key,underToCamel(map.get(key)))
                }else{
                    line = line.replace(key,map.get(key))
                }
            })
            collects.add(line)
            return
        }
    }

    static class ProcessGetMethod implements IProcessLine{

        @Override
        boolean filter(String line,Map<String,String> map) {
            return map.keySet().stream().filter({key->line.toUpperCase().contains(key.toUpperCase())}) && line.contains("get")
        }

        @Override
        process(String line,List<String> collects, Map<String,String> map) {
            map.keySet().stream().forEach({key->
                if( line.contains(key) ){
                    line = line.replaceAll(key,underToUCamel(map.get(key)))
                }
            })
            collects.add(line)
        }
    }

    static class ProcessSetMethod implements IProcessLine{

        @Override
        boolean filter(String line,Map<String,String> map) {
            return map.keySet().stream().filter({key->line.toUpperCase().contains(key.toUpperCase())}) && line.contains("set")
        }

        @Override
        process(String line,List<String> collects, Map<String,String> map) {
            String lineStr = line
            map.keySet().stream().forEach({key->
                if( lineStr.contains(key) ){
                    lineStr = lineStr.replace("set"+key,"set"+underToUCamel(map.get(key)))
                    lineStr = lineStr.replace(key,underToCamel(map.get(key)))
                }
            })
            collects.add(lineStr)
        }
    }

    static class ProcessAttr implements IProcessLine{
        // 字段前缀切除
        List<String> prefix = Arrays.asList("c_","n_")
        // Java关键字转换
        List<String> keyWords = Arrays.asList("DEFAULT","INTERFACE","ENUM","CLASS","ABSTRACT")

        @Override
        boolean filter(String line,Map<String,String> map) {
            return line.trim().startsWith("private") && !line.contains("{") && !line.contains("static")
        }

        @Override
        process(String line, List<String> collects,Map<String,String> data) {
            List<String> spiltList = Lists.newArrayList(Splitter.on(" ").trimResults().omitEmptyStrings().splitToList(line))
            if( spiltList.size() >= 3 ){
                collects.add(Strings.lenientFormat("    @JsonProperty(\"%s\")",spiltList.get(2).split(";")[0]))
            }
            try{
                String fieldName = spiltList.remove(2)
                String fieldNameSub
                prefix.stream().forEach({prefix->
                    if( fieldNameSub==null||fieldNameSub==fieldName ){
                        fieldNameSub = fieldName.replace(prefix,"")
                    }
                })
                String replaceFieldName = underToCamel(fieldNameSub)
                boolean keyWordsFlag = keyWords.contains(fieldNameSub.split(";")[0])
                spiltList.add(2,keyWordsFlag?replaceFieldName.split(";")[0]+"Value":replaceFieldName)
                collects.add("    "+spiltList.join(" "))
                if( !keyWordsFlag ){
                    data.put(fieldName.toUpperCase().split(";")[0],fieldNameSub.split(";")[0])
                    data.put(fieldName.split(";")[0],fieldNameSub.split(";")[0])
                }else{
                    data.put(fieldName.toUpperCase().split(";")[0],fieldNameSub.split(";")[0]+"_Value")
                    data.put(fieldName.split(";")[0],fieldNameSub.split(";")[0]+"_Value")
                }
            }catch(Exception e){
                println(e.getMessage())
            }
        }
    }

    static interface IProcessLine{
        boolean filter(String line,Map<String,String> map)
        Object process(String line,List<String> args,Map<String,String> data)
    }
}
